package nautilus.lab.activity;

//
//Book:      OpenGL(R) ES 2.0 Programming Guide
//Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
//ISBN-10:   0321502795
//ISBN-13:   9780321502797
//Publisher: Addison-Wesley Professional
//URLs:      http://safari.informit.com/9780321563835
//         http://www.opengles-book.com
//

//Simple_Texture2D
//
// This is a simple example that draws a quad with a 2D
// texture image. The purpose of this example is to demonstrate 
// the basics of 2D texturing
//

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.util.Log;

public class SimpleTexture2DRenderer implements GLSurfaceView.Renderer {

	private Context mContext;
 ///
 // Constructor
 //
 public SimpleTexture2DRenderer(Context context)
 {
     mContext = context;
     mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
             .order(ByteOrder.nativeOrder()).asFloatBuffer();
     mVertices.put(mVerticesData).position(0);
     mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
             .order(ByteOrder.nativeOrder()).asShortBuffer();
     mIndices.put(mIndicesData).position(0);
 }
 
 private byte[] createImageBuffer(int width, int height, String msg) {
	 int n = width * height;
	 byte[] buffer = new byte[n * 3];
	 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
	 //Typeface tf = Typeface.MONOSPACE;
	 paint.setTextSize(20.5f);
	 paint.setColor(Color.RED);
	 Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
	 Canvas canvas = new Canvas(bmp);
	 canvas.drawColor(Color.WHITE);
	 canvas.drawText(msg, 0, 0, paint);
	 
	 int pixels[] = new int[n];
	int i;
	bmp.getPixels(pixels, 0, width, 0, 0, width, height);
		for (i = 0; i < n; i++) {
			buffer[i] = (byte) ((pixels[i] >> 16) & 0x000000ff);
			buffer[i+1] = (byte) ((pixels[i] >> 8) & 0x000000ff);
			buffer[i+2] = (byte) (pixels[i] & 0x000000ff);
		}
	 
	 bmp.recycle();
	 
	 return buffer;
 }
 
 private byte[] loadImageBuffer() throws IOException {
	 byte[] buffer = null;
	 AssetManager manager = mContext.getAssets();
	 InputStream is = null;
	 try{
		int i;
		is = manager.open("testImage.png");
		Bitmap bmp = BitmapFactory.decodeStream(is);
		int width = bmp.getWidth();
		int height = bmp.getHeight();
		int n = width * height;
		int pixels[] = new int[n];
		buffer = new byte[n * 3];
		bmp.getPixels(pixels, 0, width, 0, 0, width, height);
		for (i = 0; i < n; i++) {
			buffer[i] = (byte) ((pixels[i] >> 16) & 0x000000ff);
			buffer[i+1] = (byte) ((pixels[i] >> 8) & 0x000000ff);
			buffer[i+2] = (byte) (pixels[i] & 0x000000ff);
		}
		 
		bmp.recycle();
	 }finally{
		 if(is != null) 
			 is.close();
	 }
	 return buffer;
 }

 //
 // Create a simple 2x2 texture image with four different colors
 //
 private int createSimpleTexture2D( )
 {
     // Texture object handle
     int[] textureId = new int[1];
     
     // 2x3 Image, 3 bytes per pixel (R, G, B)
//     byte[] pixels = 
//         {  
//             127,   0,   0, // Red
//             0, 127,   0, // Green
//             0,   0, 127, // Blue
//             127, 127,   0,  // Yellow
//             127, 0,   127,
//             0, 127,   127,
//         };
     //byte[] pixels = createImageBuffer(60, 27, "Hello!");
     byte[] pixels;
     InputStream is = null;
	try {
		AssetManager manager = mContext.getAssets();
		
		Bitmap bmp;
		is = manager.open("testImage.png");
		bmp = BitmapFactory.decodeStream(is);
		
	    // Use tightly packed data
	    GLES20.glPixelStorei ( GLES20.GL_UNPACK_ALIGNMENT, 1 );

	    //  Generate a texture object
	    GLES20.glGenTextures ( 1, textureId, 0 );

	    // Bind the texture object
	    GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureId[0] );

	    //  Load the texture	    
	    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);

	    // Set the filtering mode
	    GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST );
	    GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST );
	     
	    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_TEXTURE);
		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_TEXTURE);
		bmp.recycle();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally{
		 if(is != null)
			try {
				is.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
     
     return textureId[0];        
 }

 ///
 // Initialize the shader and program object
 //
 public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
 {
     String vShaderStr =
               "attribute vec4 a_position;   \n"
             + "attribute vec2 a_texCoord;   \n"
             + "varying vec2 v_texCoord;     \n"
             + "void main()                  \n"
             + "{                            \n"
             + "   gl_Position = a_position; \n"
             + "   v_texCoord = a_texCoord;  \n"
             + "}                            \n";

     String fShaderStr = 
               "precision mediump float;                            \n"
             + "varying vec2 v_texCoord;                            \n"
             + "uniform sampler2D s_texture;                        \n"
             + "void main()                                         \n"
             + "{                                                   \n"
             + "  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
             + "}                                                   \n";

     // Load the shaders and get a linked program object
     mProgramObject = loadProgram(vShaderStr, fShaderStr);

     // Get the attribute locations
     mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
     mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord" );
     
     // Get the sampler location
     mSamplerLoc = GLES20.glGetUniformLocation ( mProgramObject, "s_texture" );

     // Load the texture
     mTextureId = createSimpleTexture2D ();

     GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 }
 
 private int loadProgram(String vShaderStr, String fShaderStr) {
	//prepare shader and GL program
	 int programId;
			int vertextSharder = loadShader(GLES20.GL_VERTEX_SHADER, vShaderStr);
			int fragmentSharder = loadShader(GLES20.GL_FRAGMENT_SHADER, fShaderStr);
			
			if (vertextSharder == 0 || fragmentSharder == 0) {
				Log.e("GraphNoColorInVertexRenderer", "Load shaders failed!");
				return 0;
			}
			
			programId = GLES20.glCreateProgram();
			GLES20.glAttachShader(programId, vertextSharder);
			GLES20.glAttachShader(programId, fragmentSharder);
			
			GLES20.glLinkProgram(programId);
			
			int[] linked = { 0 };
	        GLES20.glGetProgramiv(programId, GLES20.GL_LINK_STATUS, linked, 0);
	        if (linked[0] == 0) {
	            Log.e("GraphNoColorInVertexRenderer", GLES20.glGetProgramInfoLog(programId));
	            return 0;
	        }
	        return programId;
 }
 
 public static int loadShader(int type, String shaderCode){
		int shader = GLES20.glCreateShader(type);
		int[] compiled = { 0 };
		if(shader == 0) return 0;
			
		GLES20.glShaderSource(shader, shaderCode);
		GLES20.glCompileShader(shader);
		
		GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
     if (compiled[0] == 0) {
         Log.e("Simple2DTextureRenderer", GLES20.glGetShaderInfoLog(shader));
     }
     return shader;
	}

 // /
 // Draw a triangle using the shader pair created in onSurfaceCreated()
 //
 public void onDrawFrame(GL10 glUnused)
 {
     // Set the viewport
     GLES20.glViewport(0, 0, mWidth, mHeight);

     // Clear the color buffer
     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

     // Use the program object
     GLES20.glUseProgram(mProgramObject);

     // Load the vertex position
     mVertices.position(0);
     GLES20.glVertexAttribPointer ( mPositionLoc, 3, GLES20.GL_FLOAT, 
                                    false, 
                                    5 * 4, mVertices );
     // Load the texture coordinate
     mVertices.position(3);
     GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT,
                                    false, 
                                    5 * 4, mVertices );

     GLES20.glEnableVertexAttribArray ( mPositionLoc );
     GLES20.glEnableVertexAttribArray ( mTexCoordLoc );

     // Bind the texture
     GLES20.glActiveTexture ( GLES20.GL_TEXTURE0 );
     GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, mTextureId );

     // Set the sampler texture unit to 0
     GLES20.glUniform1i ( mSamplerLoc, 0 );

     GLES20.glDrawElements ( GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices );
 }

 ///
 // Handle surface changes
 //
 public void onSurfaceChanged(GL10 glUnused, int width, int height) {
     mWidth = width;
     mHeight = height;
 }

 
 // Handle to a program object
 private int mProgramObject;
 
 // Attribute locations
 private int mPositionLoc;
 private int mTexCoordLoc;
 
 // Sampler location
 private int mSamplerLoc;
 
 // Texture handle
 private int mTextureId;
 
 // Additional member variables
 private int mWidth;
 private int mHeight;
 private FloatBuffer mVertices;
 private ShortBuffer mIndices;
 
 private final float[] mVerticesData = { 
         -0.2f, 0.2f, 0.0f, 0.0f, 0.0f, // TexCoord 0
         -0.2f, -0.2f, 0.0f, 0.0f, 1.0f, // TexCoord 1
         0.2f, -0.2f, 0.0f, 1.0f, 1.0f, // TexCoord 2
         0.2f, 0.2f, 0.0f, 1.0f, 0.0f // TexCoord 3
 };

 private final short[] mIndicesData = { 
         0, 1, 2, 0, 2, 3 
 };
 
}